/* Clara - Compile-time Approximation of Runtime Analyses
 * Copyright (C) 2009 Eric Bodden
 * 
 * This framework uses technology from Soot, abc, JastAdd and
 * others. 
 *
 * This framework is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this compiler, in the file LESSER-GPL;
 * if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
package ca.mcgill.sable.clara.fsanalysis.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import ca.mcgill.sable.clara.HasDAInfo;
import ca.mcgill.sable.clara.weaving.aspectinfo.TracePattern;
import ca.mcgill.sable.clara.weaving.weaver.depadviceopt.ds.Shadow;

import soot.SootMethod;
import abc.main.Main;
import abc.tm.weaving.aspectinfo.PerSymbolTMAdviceDecl;

/**
 * This class splits a given set of shadows into multiple sets so that each set holds only shadows of one TracePattern. 
 *
 * @author Eric Bodden
 */
public class ShadowsPerTMSplitter {
	
	/**
	 * Splits the shadows in the given set per TracePattern.
	 * Returns symbol shadows only, i.e. shadows generated by a {@link PerSymbolTMAdviceDecl}. 
	 * @param shadows a set of {@link Shadow}s
	 * @return a mapping from TracePattern to a {@link Set} of {@link Shadow}s of that TracePattern
	 */
	public static Map<TracePattern,Set<Shadow>> splitSymbolShadows(Collection<Shadow> shadows) {
		
		HashMap<SootMethod, TracePattern> adviceMethodToTracePattern = new HashMap<SootMethod, TracePattern>();
		
		HasDAInfo gai = (HasDAInfo) Main.v().getAbcExtension();
		for (TracePattern tm : gai.getDependentAdviceInfo().getTracePatterns()) {
			for (String tmSymbol : tm.getSymbols()) {
				adviceMethodToTracePattern.put(tm.getSymbolAdviceMethod(tmSymbol), tm);
			}
		}
		
		Map<TracePattern,Set<Shadow>> tmToShadows = new HashMap<TracePattern,Set<Shadow>>();

		for (Shadow shadow : shadows) {
			SootMethod adviceMethod = shadow.getAdviceDecl().getImpl().getSootMethod();
			TracePattern tm = adviceMethodToTracePattern.get(adviceMethod);
			if(tm!=null) {
				Set<Shadow> tmShadows = tmToShadows.get(tm);
				if(tmShadows==null) {
					tmShadows = new HashSet<Shadow>();
					tmToShadows.put(tm, tmShadows);
				}
				tmShadows.add(shadow);
			}
		}

		return tmToShadows;		
	}

}
